import time
import signal
import sys
import socket
import threading
import inspect
from utils import get_logger, is_ip_compliant, get_config, logger
from common import *
from queue import Queue

# logger = get_logger('Server')

class Server:
    def __init__(self, conn, addr, port, remote_name=None, self_name=None):
        """初始化一个socket框架服务

        Args:
            conn (socket.socket): 用于通信的socket
            addr (str): 目标主机地址
            port (int): 端口
        """
        # ----------目标主机的链接-----------
        self.socket: socket.socket = conn
        self.addr = addr
        self.port = port
        self.remote_name = remote_name
        # ---------------------------------
        self.name = self_name
        self.running = threading.Event()
        self.channel: dict[str, Queue] = {}  # {channel_name: Queue()} channel接收消息队列
        self.send_queue: Queue = Queue(100)  # 发送消息队列
        self.processor = {}  # {processor: [MessageType]}
        self.config = None
        # -------------相关的锁--------------
        self.registered = threading.Event()

        self.processor_mapping: dict[MessageType, str] = {}  # {MessageType: processor_name}

    def _handle_core(self):
        """处理客户端连接"""
        try:
            self._recv_msg()
        except (ConnectionResetError, BrokenPipeError, socket.error) as e:
            logger.error(f"Handle client message error: {e}")
            self.send_message({'type': MessageType.Refuse, 'message': f"Handle client message error: {e}"})
        except Exception as e:
            logger.error(f"Unexpected error in _handle_core: {e}")
        finally:
            logger.info(f"The server [{self.addr}: {self.port}] is disconnected")
            self.stop()


    def start(self):
        if self.running.is_set():
            logger.warning('The service is running and cannot be invoked more than once')
            return
        if self.processor == {}:
            raise Exception('The processor needs to be set up before it can run')

        self.running.set()
        # TODO 读取配置文件
        # self.config = get_config("./config.cfg")
        self.add_processor(self.processor)
        threading.Thread(target=self._send_msg, daemon=True).start()
        self._handle_core()
        logger.info(f'The remote service [{self.remote_name}-{self.addr}:{self.port}] has been stopped')
    
    def stop(self):
        if self.running.is_set():
            self.registered.clear()
            logger.info(f"The Service [{self.addr}] Registration Cancellation.")
            self.running.clear()
            logger.info(f"The Service [{self.addr}] Has Stopped Running.")
            self.socket.close()
            logger.info(f"The Service [{self.addr}] Conection Is Stopped.")

    def set_processor(self, processors: dict[callable, list[MessageType]]):
        self.processor = processors
    
    def add_processor(self, processors: dict[callable, list[MessageType]]):
        """每个类型可对应多个处理器, 但每个处理器只能对应一个类型"""
        threads = []
        for processor, type_list in processors.items():
            self.channel[processor.__name__] = Queue()  # 创建队列
            for msg_type in type_list:
                self.processor_mapping[msg_type] = processor.__name__
            threads.append(threading.Thread(target=processor, args=(self,), daemon=True))

        logger.info(f'[{self.name} server] Add processor success')
        for processor in threads:
            processor.start()
        logger.info(f'[{self.name} server] Start processor success')

    def get_message(self):
        """获取对应Channel的消息
        
        Returns:
            message: 消息
        """
        stack = inspect.stack()
        caller_frame = stack[1]
        caller_function_name = caller_frame.function
        try:
            msg = self.channel[caller_function_name].get()
        except KeyError:
            logger.error(f'Channel is a dict, but {caller_function_name} key is not in channel')
            raise KeyError(f'Channel is a dict, but {caller_function_name} key is not in channel')
        return msg
    
    def send_message(self, message: dict, channel_name: str=None):
        """发送消息到对应Channel
        
        Args:
            message: 消息
            channel_name: Channel名称. 可进行线程间的通信
        """
        if channel_name is None:
            self.send_queue.put(message)
        else:
            try:
                self.channel[channel_name].put(message)
            except Exception as e:
                logger.error(f"Failed to put message into channel {channel_name}: {e}")

    def _send_msg(self):
        while self.running.is_set():
            msg = self.send_queue.get()
            try:
                MessageProtocol.send(self.socket, msg)
            except (ConnectionResetError, BrokenPipeError, socket.error) as e:
                logger.error(f"[{self.name}-{self.remote_name}] Failed to send message: {e}")
                self.stop()
            # logger.debug(f"[{self.name} server] Send message\ndata: type: {MessageType(msg['type'])}-{msg}")

    def _recv_msg(self):
        while self.running.is_set():
            try:
                msg = MessageProtocol.recv(self.socket)
                if not msg:
                    break
                # logger.debug(f'[{self.name} server] Recv message\ndata: {msg}')
                if msg['type'] in self.processor_mapping:
                    self.channel[self.processor_mapping[msg['type']]].put(msg)
                else:
                    logger.error(f'[{self.name} server] Message type {msg["type"]} is not in _type_map. So discard')
            except (ConnectionResetError, BrokenPipeError, socket.error) as e:
                logger.error(f"Failed to receive message: {e}")
                break
            except Exception as e:
                logger.error(f"Unexpected error in _recv_msg: {e}")
                break
    
    # 不用
    def is_socket_available(self, timeout: float = 2) -> bool:
        """
        检查给定的socket连接是否可用
        """
        conn = self.socket
        if not isinstance(conn, socket.socket):
            raise ValueError("conn must be a socket.socket object")

        # 设置超时时间
        conn.settimeout(timeout)

        try:
            # 发送心跳消息（例如，一个空消息或特定类型的消息）
            heartbeat_message = {'type': MessageType.Heartbeat, 'message': 'ping'}
            MessageProtocol.send(conn, heartbeat_message)

            # 等待响应
            start_time = time.time()
            while time.time() - start_time < timeout:
                response = MessageProtocol.recv(conn)
                if response and response['type'] == MessageType.Heartbeat:
                    return True
                time.sleep(0.1)  # 避免CPU占用过高
        except (socket.error, socket.timeout) as e:
            logger.error(f"Socket availability check failed: {e}")
        except Exception as e:
            logger.error(f"Unexpected error during socket availability check: {e}")

        return False

def server_start():
    print('Server start')

if __name__ == '__main__':
    d : dict[callable, list[MessageType]] = {
        server_start: [MessageType.Register],
    }
    for k in d.keys():
        print(k.__name__)
        k()